/***************************************************************************
 *   Copyright (C) 2007 by Alexandre Masselot,,,   *
 *   alex@alex-laptop   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef BOLPEAKINTENSITY_H
#define BOLPEAKINTENSITY_H

#include <math.h>

#ifdef HAVE_BOOST_SERIALIZATION
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#endif

#ifdef HAVE_PROTOBUF
#ifdef _MSC_VER
// we don't create DLLs and thus don't need to pay attention to this warning
#pragma warning( disable: 4251 )
#endif
#include "runlcmsms.pb.h"
#endif

#include "peak.h"

namespace bol {

/**
  PeakIntensity extends Peak class, with an double memeber for intensity, nad an unsigne int one for intensity rank (if the peak is to be withi a collection). This rank is set to 0 for the first to n-1 for the last (or n-2 for the two last if they have equal intensities) etc.

  To get a float rank, just ask for 1-intensityRank/size().

  @author Alexandre Masselot,,, <alex@alex-laptop>
 */
  class PeakIntensity:public Peak{
    private:
      mutable double m_intensity; // mutable instead of const : in a few corner case, the intensity might not be known when creator is called
      unsigned int m_intensityRank;

#ifdef HAVE_BOOST_SERIALIZATION
      // *** BOOST serialisation code ***
      friend class boost::serialization::access; // gives access to serialisator
      template<class Archive> void serialize ( Archive & ar, const unsigned int version ) const
      {
        // base class serialisation - warning, as there are several variable, the order is critical...
        // ... well not for XML. But for most other archive types.
        ar & boost::serialization::make_nvp("Peak", boost::serialization::base_object<Peak> ( *this ));

        ar & boost::serialization::make_nvp("intensity", m_intensity);
        // Rank is a computed value so we don't save it.
      }
#endif

    public:
  
  /**
     * full constructor, intensityRank is set to INT_MAX
     * @param m m/z
     * @param charges charge mask (warning, it is a bitset, no directly the charge, see Peak doc for more details)
     * @param i intensity
   */
      PeakIntensity(const double m, const Pchargemask charges=0, const double i=0.):Peak(m, charges), m_intensity(i){
        m_intensityRank=INT_MAX;
      }

  /**
       * idem as previous, where the charges are read from the string (see @Peak doc for more details)
       * @param m
       * @param charges
       * @param i
   */
      PeakIntensity(const double m, const string charges, const double i):Peak(m, charges), m_intensity(i){
        m_intensityRank=INT_MAX;
      }


      ~PeakIntensity(){}

  /**
       * comparison operator (for vector like sort) based on the intensity
       * @param pa
       * @param pb
       * @return
   */
      static bool cmpIntensity(const PeakIntensity& pa, const PeakIntensity& pb){
        if(pa.intensity()<pb.intensity()){
          return true;
        }else if(pa.intensity()==pb.intensity()){
          return (pa.moz()<pb.moz());
        }
        return false;
      }

      friend ostream& operator<<(ostream& out, const PeakIntensity& p);
      friend ostream& operator<<(ostream& out, const PeakIntensity* p);

  /**
       *
       * @return the peak intensity (whatever the source )
   */
      double intensity() const {
        return m_intensity;
      }

      double setIntensity(double i) {
        // in a few corner case, the intensity might not be known when creator is called
        return m_intensity = i;
      }

      void setIntensityRank(unsigned int theValue) {
        m_intensityRank = theValue;
      }

  /**
       * the rank of the peak (only meaningfull if the peak is contained into an context (such as Spectrum<PeakIntensity>)
       * most intense peak is set to 0, second to 1.. if peak have the same intensities, they have the rank of the highest (but all are counted to attribute the rank of the next most intense peak)
       * @return the rank
   */
      unsigned int intensityRank() const {
        return m_intensityRank;
      }
  
  

  };

#ifdef HAVE_PROTOBUF
  static inline bool operator<< (protobuf::RunLcmsms::Spectrum::Peak& pb, const class PeakIntensity& p) {
    if (p.intensity() > 0.)
      pb.set_intensity(p.intensity());
    pb << static_cast< class Peak > (p);
    return true;
  }

  static inline bool operator>> (const protobuf::RunLcmsms::Spectrum::Peak& pb, class PeakIntensity& p) {
    // intensity is set by constructor when peak is allocated
    (pb) >> (static_cast< class Peak &> (p));
    return true;
  }
#endif

}

#ifdef HAVE_BOOST_SERIALIZATION
#if defined(WIN32) && (BOOST_VERSION < 103600)
// other wise Visual Studio spits error messages
#include <boost/serialization/extended_type_info_typeid.hpp>
#endif
BOOST_CLASS_EXPORT_GUID(bol::PeakIntensity, "PeakIntensity") // register GUID
#endif

#endif
